
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Gui.AspNet2;
using Swaf.Security;

[assembly: WebResource("ScsAspNet.Syrinx.Gui.AspNet.Ajax.script.ExtendedGrid.js", "application/x-javascript")]
namespace Syrinx.Gui.AspNet.Ajax
{
	public class Grid : Nitobi.Grid, IBizObjListDisplay2, IAjaxClientControl
	{
		protected static string s_ajaxUrl = "/NitobiLiveStreamHandler.aspx?pi={0}&bpi={1}";

		protected string m_dataDetailBizRule = null;
		protected string m_dataSourceBizRule = null;
		protected object m_dataSourceBizRuleParam = null;
		protected Privileges m_editPriv = Privileges.ReadOnly;
		protected int m_maxElements = -1;
		protected string m_parentBizProcIds = null;
		protected bool m_createOnLoad = true;
		protected bool m_mySelectEvent = false;
		protected bool m_updateOnRowChanged = true;
		protected bool m_ajaxEventOnRowSelect = true;
		protected bool m_eventNeedsRefresh = false;
		protected string m_clientBizObjMods = null;
		protected bool m_processedAjaxUpdateData = false;
        protected bool m_refreshGridFromColChange = false;

		public Grid()
			:base()
		{
		}

		public Grid(ActiveWidget widget)
		{
			ID = widget.State.Id;
		}

		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			if (m_createOnLoad)
			{
				WidgetOfflineState offlineState = State;
				ActiveWidget act = new ActiveWidget(this, BPC, offlineState);
				BPC.defineActiveWidget(act);
			}
			else
				m_columns = State.State["columns"] as Nitobi.ColumnsEntity;

			Page.ClientScript.RegisterClientScriptBlock(typeof(Grid), "PerGrid"+ClientID,
				string.Format(@"
	function {1}RowSel(g,ri)
	{{
		if(g.inHtmlRead)
			return;
		var d=g.datatable.xmlDoc.selectSingleNode('//'+nitobi.xml.nsPrefix+'data/'+nitobi.xml.nsPrefix+'e[@xi='+ri+']');
		var k = d.getAttribute('xk');
		{0}BizProc.triggerEvent('{1}', 'bizObjSelected', k);
		//document.getElementById('testout').innerHTML += 'xx<br/>';
		//alert('wait');
		//debugger;
	}}
	var {1}ParentBizProc = '{0}BizProc';
",
			ParentBizProcIds, ClientID), true);

			if (AjaxEventOnRowSelect)
				ClientEvents.RowFocus = ClientID + "RowSel(arguments[1].grid, arguments[1].row.row);";

			ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			string url = string.Format(s_ajaxUrl, BPC.PageState.PageId, bizproc.OfflineState.Id);
			this.GetDataUrl = url;
		}

        protected override string WrapperDivAttributes
        {
            get
            {
                return string.Format("id='{0}'", OuterDivClientId);
            }
        }

        protected virtual string OuterDivClientId { get { return ClientID + "Outer"; } }

		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
			string scriptUrl = Page.ClientScript.GetWebResourceUrl(typeof(Grid), "ScsAspNet.Syrinx.Gui.AspNet.Ajax.script.ExtendedGrid.js");
			Page.ClientScript.RegisterClientScriptInclude("SwafGrid.ExtendedGridScript", scriptUrl);
			if(UpdateOnRowChange)
				ClientEvents.AfterCellEdit = "gridCellEditComplete(eventArgs)";
			State.State["columns"] = Columns;
		}

		protected BizProcCoordinator BPC
		{
			get { return (Page is IPage) ? ((IPage)Page).BPC : null; }
		}

		protected WidgetOfflineState State
		{
			get
			{
				WidgetOfflineState state = BPC == null ? null : BPC.getWidgetOfflineState(WidgetId);
				if (state == null && BPC != null)
				{
					BPC.addWidgetOfflineState(state = new WidgetOfflineState(WidgetId, this.GetType().AssemblyQualifiedName));
					state.setParentBizProcIds(m_parentBizProcIds);
					state.BizProcWidgetType = this.BizProcWidgetType;
				}
				return state;
			}
		}

		#region IBizObjListDisplay Members
		protected bool m_drivenByBizProc = true;
		public bool DrivenByBizProc { get { return (bool)getOffline("m_drivenByBizProc"); } set { putOffline("m_drivenByBizProc", value); } }

		public event BizObjChanged BizObjAdded;
		public event BizObjChanged BizObjDeleted;
		public event BizObjSelectedInfo BizObjSelected;
		public event BizObjChanged BizObjUpdated;

		public string DataDetailBizRule { get { return m_dataDetailBizRule; } set { m_dataDetailBizRule = value; } }
		public string DataSourceBizRule { get { return m_dataSourceBizRule; } set { m_dataSourceBizRule = value; } }
		public string DataSourceBizRuleParam { get { return m_dataSourceBizRuleParam as string; } set { m_dataSourceBizRuleParam = value; } }

		public Privileges EditPrivilege { get { return m_editPriv; } set { m_editPriv = value; } }
		public string MaxElements { get { return m_maxElements.ToString(); } set { m_maxElements = int.Parse(value); } }
		public bool UpdateOnRowChange {get{return m_updateOnRowChanged;}set{m_updateOnRowChanged = value;}}
        public bool AjaxEventOnRowSelect { get { return m_ajaxEventOnRowSelect; } set { m_ajaxEventOnRowSelect = value; } }

        public bool RefreshGridFromColumnChange { get { return m_refreshGridFromColChange; } set { m_refreshGridFromColChange = value; } }

		public IBizObj SelectedBizObj
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public object SelectedBizObjKeyValue
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				if (Cmn.IsEmpty(value))
					base.SelectedRowIds = new string[] { };
				else
					base.SelectedRowIds = new string[] { value.ToString() };
			}
		}

		public void getSelectedBizObjs(IBizObjList selected)
		{
			string[] rowIds = SelectedRowIds;
			if (rowIds != null && rowIds.Length > 0)
			{
				IBizObjList d = Data.provider().getDataSource() as IBizObjList;
				if (d != null)
				{
					foreach (string strId in rowIds)
					{
						object bizobjKeyValue = d.objectType.convertValueToKeyType(strId);
						selected.Add(d.search(d.objectType.KeyFieldNames, bizobjKeyValue));
					}
				}
			}
		}

		public void setSelectedBizObjs(IBizObjList selected)
		{
			if (selected != null)
			{
				SelectedRowIds = new string[selected.Count];
				for (int p = 0; p < selected.Count; p++)
					SelectedRowIds[p] = selected[p].KeyValue.ToString();
			}
		}

		public void showBizObjs(IBusinessProcess bizproc, IBizObjCursor cur)
		{
			IBizObjList list = cur.Source;
			Data.provider().setDataSource(list);
		}

		public void updateBizObjs()
		{
			//throw new NotImplementedException();
		}

		public virtual void refresh()
		{
			m_eventNeedsRefresh = true;
		}
		#endregion

		#region IWidget Members

		public BizProcWidgetType BizProcWidgetType { get { return BizProcWidgetType.list; } set { } }

		public string ParentBizProcIds { get { return m_parentBizProcIds; } set { m_parentBizProcIds = value; } }

		public string WidgetId
		{
			get { return ClientID; }
		}

		#endregion

		#region IAjaxClientControl Members

		public void setState(System.Xml.XmlElement clientState)
		{
			ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
			string ajaxEvent = clientState.OwnerDocument.DocumentElement.GetAttribute("event").ToLower();
			bool mybizProc = clientState.OwnerDocument.DocumentElement.GetAttribute("bizProcId").CompareTo(bizproc.OfflineState.Id) == 0;
			if (ajaxEvent.CompareTo("bizobjselected") == 0 && mybizProc)
				m_mySelectEvent = true;
			else// if (mybizProc)
				m_eventNeedsRefresh = true;

			string selRows = clientState.GetAttribute("selectedRows");
			if (!Cmn.IsEmpty(selRows))
				m_selectedRowInfoField.Value = selRows;

			string updatesXml = clientState.GetAttribute("updates");
			if (!Cmn.IsEmpty(updatesXml))
			{
			    m_mySelectEvent = false;
			    m_clientBizObjMods = updatesXml;
			    processClientMods();
			    clientState.RemoveAttribute("updates");
			}
		}

		public void getState(System.Xml.XmlElement clientState, string pageHtml)
		{
			if (m_eventNeedsRefresh)
				clientState.SetAttribute("refresh", "true");

            IBizObjList d = Data.provider().getDataSource() as IBizObjList;
			if (d != null)
				clientState.SetAttribute("rowCount", d.numElements.ToString());

            if (RefreshGridFromColumnChange)
            {
            }
		}

		public void processAjaxEvent(System.Xml.XmlElement eventInfo)
		{
			if (eventInfo.GetAttribute("event").CompareTo("bizObjSelected") == 0)
			{
				string bizObjId = eventInfo.GetAttribute("value");
				ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				bizproc.BizProc.selectBizObj(bizObjId, this);
			}
			else if (eventInfo.GetAttribute("event").CompareTo("bizObjUpdated") == 0)
			{
				ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				Data.provider().setDataSource(bizproc.BizProc.SourceBizObjs);
				m_clientBizObjMods = eventInfo.GetAttribute("value");
				processClientMods();
			}
			else if (eventInfo.GetAttribute("event").CompareTo("addBizObj") == 0)
			{
				ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				IBizObj obj = bizproc.BizProc.createNewBizObj();
				bizproc.BizProc.updateBizObj(obj);
			}
		}

		public bool CreateOnLoad { set { m_createOnLoad = value; } }

		public bool NeedToGenerateHtmlWithServerControls { get { return false; } }

		#endregion

		protected virtual void processClientMods()
		{
			if(m_columns.Columns.Count == 0 && State.State["columns"] is  Nitobi.ColumnsEntity)
				m_columns = State.State["columns"] as Nitobi.ColumnsEntity;

			if (!m_processedAjaxUpdateData && m_clientBizObjMods != null && Columns.Columns.Count > 0)
			{
				ActiveBizProc bizproc = BPC.getActiveBizProc(State.ParentBizProcIds[0]);
				//IBizObjList bizObjs = Data.provider().getDataSource() as IBizObjList;
				IBizObjList bizObjs = bizproc.BizProc.SourceBizObjs;
				Nitobi.AjaxSaveDataHandlerEventArgs saveInfo = new Nitobi.AjaxSaveDataHandlerEventArgs(m_clientBizObjMods, Columns);
				m_clientBizObjMods = null;
				m_processedAjaxUpdateData = true;
				for (int p = 0; p < saveInfo.Count; p++)
				{
					Nitobi.IRow row = saveInfo[p];
					switch (row.UpdateAction)
					{
						case Nitobi.UpdateAction.Delete:
							bizproc.BizProc.deleteBizObj(row.RowKey);
							break;
						case Nitobi.UpdateAction.Update:
							object rowKey = bizObjs.objectType.convertValueToKeyType(row.RowKey.ToString());
							IBizObj mod = bizObjs.search(bizObjs.objectType.KeyFieldNames, rowKey);
							if (mod == null)
								mod = bizproc.BizProc.getBizObj(row.RowKey);
							if (mod == null)
							{
								mod = bizproc.BizProc.createNewBizObj();
								mod.put(mod.type.KeyFieldNames, rowKey);
							}
							if (mod != null)
							{
								mod.clearDirtyFlags();
								foreach(Nitobi.Column c in Columns.Columns)
									if (c.getContributesToData() && !mod.isDirty(c.Name) && string.Compare(covertToString(mod.get(c.Name)), covertToString(row[c.Name])) != 0)
										mod.put(c.Name, row[c.Name]);
								bizproc.BizProc.updateBizObj(mod);
							}
							break;
						case Nitobi.UpdateAction.Insert:
							IBizObj obj = bizproc.BizProc.createNewBizObj();
							foreach (Nitobi.Column c in Columns.Columns)
								if (c.getContributesToData() && !obj.isDirty(c.Name) && string.Compare(covertToString(obj.get(c.Name)), covertToString(row[c.Name])) != 0)
									obj.put(c.Name, row[c.Name]);
							bizproc.BizProc.updateBizObj(obj);
							break;
					}
				}
				m_clientBizObjMods = null;
			}
		}
		protected string covertToString(object val)
		{
			return val == null ? "" : val.ToString();
		}
		protected void putOffline(string keyName, object val)
		{
			if (BPC != null)
				State.State.put(keyName, val);
			Cmn.callPropertySet(this, keyName, val);
		}
		protected object getOffline(string keyName)
		{
			object v = BPC == null ? null : State.State.get(keyName);
			if (v == null)
				v = Cmn.callPropertyGet(this, keyName);
			return v;
		}
	}
}
